package se.thoka.twt.client.utils;

import com.google.gwt.core.client.GWT;

/**
 * @author Thobias Karlsson, Thoka
 * @since 8 jan 2010
 */
public class TWTLogger {

	private static final boolean consoleFromStart;
	private static final boolean isClient;
	private static TWTLogLevel logLevel;
	private static boolean enabled, alertsEnabled;

	static {
		isClient = GWT.isClient();
		consoleFromStart = isClient ? hasConsole() : false;
		logLevel = TWTLogLevel.INFO;

		alertsEnabled = false;

		enabled = false;
	}

	/**
	 * Logs a message to the system/browser, will use log level <code>TRACE</code>
	 * 
	 * @param s A log message, may be <code>null</code>
	 */
	public static void log(String s) {
		log(s, null);
	}

	/***
	 * Logs a message to the system/browser, will use log level <code>TRACE</code>
	 * 
	 * @param s A log message, may be <code>null</code>
	 * @param e A thrown exception, may be <code>null</code>
	 */
	public static void log(String s, Throwable e) {
		log(TWTLogLevel.TRACE, s, e);
	}

	/**
	 * Logs a message to the system/browser
	 * 
	 * @param level The log level
	 * @param s A log message, may be <code>null</code>
	 */
	public static void log(TWTLogLevel level, String s) {
		log(level, s, null);
	}

	/**
	 * Logs a message to the system/browser
	 * 
	 * @param level The log level
	 * @param s A log message, may be <code>null</code>
	 * @param e A thrown exception, may be <code>null</code>
	 */
	public static void log(TWTLogLevel level, String s, Throwable e) {
		if (isEnabled()) {
			if (level == null) {
				level = TWTLogLevel.TRACE;
			}
			if (level.ordinal() >= logLevel.ordinal()) {
				if (isClient()) {
					level.logGWT(s, e);

					if (s != null) {
						level.logConsole(s);
					}
					if (e != null) {
						level.logConsole(e);
					}
				} else {
					level.logSystem(s, e);
				}
			}
		}
	}

	/**
	 * @return The log level
	 */
	public static TWTLogLevel getLogLevel() {
		return TWTLogger.logLevel;
	}

	/**
	 * @return <code>true</code> if alerts may be used in browsers that does not support <code>console</code>
	 */
	public static boolean isAlertsEnabled() {
		return TWTLogger.alertsEnabled;
	}

	/**
	 * @return <code>true</code> if logger is enabled
	 */
	public static boolean isEnabled() {
		return TWTLogger.enabled;
	}

	/**
	 * @param enabled Set <code>true</code> to allow logging to alerts when <code>console</code> is unsupported by browser
	 */
	public static void setAlertsEnabled(boolean enabled) {
		if (isClient()) {
			if (!consoleFromStart) {
				if (enabled) {
					bindAlertToConsole();
				} else {
					unbindAlertFromConsole();
				}
			}
			alertsEnabled = enabled;
		}
	}

	/**
	 * @param enabled Set <code>true</code> to enable this logger
	 */
	public static void setEnabled(boolean enabled) {
		TWTLogger.enabled = enabled;
	}

	/**
	 * Sets the log level.
	 * 
	 * <p>
	 * <i>Note: {@link TWTLogLevel#TRACE} will probably spam the hell out of you!</i>
	 * </p>
	 * 
	 * @param logLevel The log level to set
	 */
	public static void setLogLevel(TWTLogLevel logLevel) {
		if (logLevel != null) {
			TWTLogger.logLevel = logLevel;
		} else {
			throw new NullPointerException(TWTLogger.class.getName() + "#setLogLevel() - Level must not be null");
		}
	}

	/**
	 * @return <code>true</code> if code is running on client
	 */
	public static boolean isClient() {
		return isClient;
	}

//	private static void printStatus() {
//		String message;
//		if (isClient) {
//			message = "Client GWTLogger (" + (enabled ? "ENABLED" : "DISABLED") + "). Log level: " + logLevel + " (console? " + consoleFromStart + ", alertLog? " + alertsEnabled + ")";
//		} else {
//			message = "Server GWTLogger (" + (enabled ? "ENABLED" : "DISABLED") + "). Log level: " + logLevel;
//		}
//
//		if (consoleFromStart) {
//			TWTLogLevel.INFO.logConsole(message);
//		}
//		if (isClient) {
//			TWTLogLevel.INFO.logGWT(message, null);
//		} else {
//			TWTLogLevel.INFO.logSystem(message, null);
//		}
//	}

	private static native boolean hasConsole() /*-{
		if (window.console) {
			return true;
		} else {
			return false;
		}
	}-*/;

	private static native void bindAlertToConsole() /*-{
		window.console = window.console;
		if (!window.console) {
			window.console = {
				log: alert,
				info: alert,
				dir: alert,
				warn: alert,
				error: alert
			};
		}
	}-*/;

	private static native void unbindAlertFromConsole() /*-{
		window.console = window.console;
		if (window.console) {
			window.console = null;
		}
	}-*/;
}
